home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #41 (Feb 89) / window source / Window1.p < prev   
Text File  |  1988-10-02  |  28KB  |  1,120 lines

  1. (*
  2.  
  3. © 1988, Apple Computer, Inc.
  4. All rights reserved.
  5.  
  6. Window1.p:        A HyperCard XCMD in MPW Pascal 2.0.2 by Joe Zuffoletto
  7.                 Version 1.0, 29 June 1988
  8.  
  9. Form:            window title,top,left,bottom,right
  10.  
  11. Example:        window "My Window",50,100,300,400
  12.  
  13. Notes:            Window puts up a standard document window with scroll bars.
  14.                 The window can be dragged, resized, zoomed, and closed.
  15.                 
  16.                 Command-W is supported for closing the window. Command-spacebar
  17.                 toggles the menubar on and off, as in HyperCard.  If you
  18.                 try to draw the window's title bar off the screen or under
  19.                 the menubar, Window will abort with an error message. Error
  20.                 messages can be examined by looking at HyperCard's global
  21.                 variable "the result" after calling Window.
  22.                 
  23.                 Window is MultiFinder friendly and works with HyperCard 1.2
  24.                 or later.  It supports multiple displays on the Mac II as well. 
  25.                 
  26.                 You must supply your own code for displaying whatever you
  27.                 want to display in the window.
  28.                 
  29. -----------------------------------------------------------------------------
  30.  
  31. To compile and link this file using MPW Pascal 2.0.2, select the following lines
  32. and press ENTER:
  33.  
  34. Pascal Window1.p
  35. link    -o "Hard Disk":HyperCard:"HyperCard Stacks":Home ∂
  36.        -rt XCMD=2000 -sn Main=Window ∂
  37.         Window1.p.o {MPW}Libraries:Interface.o ∂
  38.         {MPW}PLibraries:PasLib.o ∂
  39.         -m ENTRYPOINT
  40.         
  41. Use other link files as necessary.
  42.  
  43. The above link directives install the XCMD resource into the Home stack. You
  44. can substitute the name of any stack you want; be sure to provide the
  45. correct pathname. Also, make sure the target stack already has a resource
  46. fork or it won't work. You can create an empty resource fork in a stack
  47. with ResEdit.
  48.  
  49. -----------------------------------------------------------------------------
  50.  
  51. *)
  52.  
  53. {$R-}
  54.  
  55. {$S Window}
  56.  
  57. UNIT DummyUnit;
  58.  
  59. INTERFACE
  60.  
  61. USES MemTypes,QuickDraw,OSIntf,ToolIntf,PasLibIntf,HyperXCmd;
  62.  
  63. PROCEDURE EntryPoint(paramPtr:XCmdPtr);
  64.  
  65. IMPLEMENTATION
  66.  
  67. TYPE    Str31    =    String[31];
  68.  
  69.         OffScrHandle    =    ^OffScrRecPtr;                {Attach to refCon of a window}
  70.         OffScrRecPtr    =    ^OffScrRecord;
  71.         OffScrRecord    =    RECORD
  72.                                 {Next month!}
  73.                             END;
  74.  
  75.         ScrollHandle    =    ^ScrollPtr;                    {Attach to refCon of a scroll bar}
  76.         ScrollPtr        =    ^ScrollRecord;
  77.         ScrollRecord    =    RECORD
  78.                                 {Next month!}
  79.                             END;
  80.  
  81.  
  82. PROCEDURE Window(paramPtr:XCmdPtr);FORWARD;
  83.  
  84.  
  85. PROCEDURE EntryPoint(paramPtr:XCmdPtr);
  86. BEGIN
  87.     Window(paramPtr);
  88. END;
  89.  
  90.  
  91. FUNCTION Min(int1,int2:INTEGER): INTEGER;
  92.  
  93. BEGIN
  94.     {Next month!}
  95. END; {Min}
  96.  
  97.     
  98. PROCEDURE InitBlit(theWindow:WindowPtr);
  99.  
  100. BEGIN
  101.     {Next month!}
  102. END; {InitBlit}
  103.  
  104.  
  105. PROCEDURE InvalContents(theWindow:WindowPtr;theOldSize:Rect);
  106.  
  107. BEGIN
  108.     {More to come next month!}
  109.     EraseRect(theWindow^.portRect);
  110.     InvalRect(theWindow^.portRect);
  111. END; {InvalContents}
  112.     
  113.     
  114. PROCEDURE DrawContents(theWindow:WindowPtr);
  115.  
  116. BEGIN
  117.     {Next month!}
  118. END; {DrawContents}
  119.     
  120.     
  121. PROCEDURE ScrollContents(theWindow:WindowPtr;dh,dv:INTEGER);
  122.  
  123. BEGIN
  124.     {Next month!}
  125. END; {ScrollContents}
  126.     
  127.     
  128. PROCEDURE MyScroll(theControl:ControlHandle;partCode:INTEGER);
  129.  
  130. BEGIN
  131.     {Next month!}
  132. END; {MyScroll}
  133.     
  134.  
  135. PROCEDURE Window(paramPtr:XCmdPtr);
  136.     
  137. CONST
  138.     minParamCount        =    5;
  139.     smallestHeight        =    100;
  140.     smallestWidth        =    100;
  141.     _WaitNextEvent        =    $A860;
  142.     _Unimplemented        =    $A89F;
  143.     active                =    0;
  144.     inactive            =    255;
  145.     MouseMovedEvt        =    $FA;
  146.     SuspendResumeEvt    =    $01;
  147.     SuspendEventMask    =    $1;
  148.     ConvertScrapMask    =    $2;
  149.     browseTool            =    6069;
  150.     HCWidth                =    512;
  151.     HCHeight            =    342;
  152.     padding                =    16;
  153.             
  154. VAR
  155.     toolVis,patVis:                BOOLEAN;
  156.     msgVis,fatVis:                BOOLEAN;
  157.     hasWaitNextEvent:            BOOLEAN;
  158.     inBackGround,smallScreen:    BOOLEAN;
  159.     DoneFlag,HaveEvent:            BOOLEAN;
  160.     menuWasHidden:                BOOLEAN;
  161.     wTop,wLeft,wBottom,wRight:    INTEGER;
  162.     partCode,controlCode:        INTEGER;
  163.     largestHeight,largestWidth:    INTEGER;
  164.     dummy,charCode:                INTEGER;
  165.     screenWidth,screenHeight:    INTEGER;
  166.     myDocWidth,myDocHeight:        INTEGER;
  167.     eventPoint:                    Point;
  168.     wRect,screenRect,dragRect:    Rect;
  169.     winSizeLimits:                Rect;
  170.     oldSize:                    Rect;
  171.     newSize,dontCare:            LONGINT;
  172.     envError:                    OSErr;
  173.     cursorRgn:                    RgnHandle;
  174.     hScroll,vScroll:            ControlHandle;
  175.     whichControl:                ControlHandle;
  176.     myWindow,whichWindow:        WindowPtr;
  177.     fatBitsWindow:                WindowPtr;
  178.     HCrefresh:                    Str31;
  179.     wT,wL,wB,wR,wTitle:            Str255;
  180.     toolStr,patStr,msgStr:        Str255;
  181.     widthStr,heightStr:            Str255;
  182.     myBits:                        BitMap;
  183.     theEnv:                        SysEnvRec;
  184.     myEvent:                    EventRecord;
  185.     wRecord:                    WindowRecord;
  186.     HCPort:                        GrafPtr;
  187.     theOffScrHandle:            OffScrHandle;
  188.     theScrollHandle:            ScrollHandle;
  189.     myOffScr:                    OffScrRecord;
  190.     myScrollRecord:                ScrollRecord;
  191.         
  192.     
  193.     FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType):BOOLEAN;
  194.  
  195.     {Check to see if a given trap is implemented.}
  196.  
  197.     BEGIN
  198.         TrapAvailable := NGetTrapAddress(tNumber, tType) <> GetTrapAddress(_Unimplemented);
  199.     END; {TrapAvailable}
  200.  
  201.  
  202.     FUNCTION CreateHScrollBar(theWindow:WindowPtr;theValue,theMin,theMax:INTEGER;theRefCon:LONGINT):ControlHandle;
  203.     VAR
  204.         myWindowRect,hScrRect : Rect;
  205.         
  206.     {Allocate and draw a horizontal scroll bar in theWindow.
  207.      Return a controlHandle to the scroll bar.}
  208.      
  209.     BEGIN
  210.         SetPort(theWindow);
  211.         myWindowRect := theWindow^.portRect;
  212.         SetRect(hScrRect,myWindowRect.left -1,
  213.                          myWindowRect.bottom - 15,
  214.                          myWindowRect.right - 14,
  215.                          myWindowRect.bottom + 1);
  216.         CreateHScrollBar := NewControl(theWindow,hScrRect,'MyHoriz',TRUE,
  217.                                         theValue,theMin,theMax,scrollBarProc,theRefCon);
  218.     END; {CreateHScrollBar}
  219.     
  220.         
  221.     FUNCTION CreateVScrollBar(theWindow:WindowPtr;theValue,theMin,theMax:INTEGER;theRefCon:LONGINT):ControlHandle;
  222.     VAR
  223.         myWindowRect,hScrRect : Rect;
  224.         
  225.     {Allocate and draw a vertical scroll bar in theWindow.
  226.      Return a controlHandle to the scroll bar.}
  227.      
  228.     BEGIN
  229.         SetPort(theWindow);
  230.         myWindowRect := theWindow^.portRect;
  231.         SetRect(hScrRect,myWindowRect.right -15,
  232.                          myWindowRect.top - 1,
  233.                          myWindowRect.right + 1,
  234.                          myWindowRect.bottom - 14);
  235.         CreateVScrollBar := NewControl(theWindow,hScrRect,'MyVert',TRUE,
  236.                                         theValue,theMin,theMax,scrollBarProc,theRefCon);
  237.     END; {CreateVScrollBar}
  238.     
  239.     
  240.     PROCEDURE InvalScroll(theWindow:WindowPtr);
  241.     VAR
  242.         theRect,tallRect,wideRect : Rect;
  243.         
  244.     {Accumulate the rectangles occupied by theWindow's
  245.      horizontal and vertical scroll bars into the update
  246.      region.}
  247.  
  248.     BEGIN
  249.         SetPort(theWindow);
  250.         theRect := theWindow^.portRect;
  251.         ClipRect(theRect);
  252.         
  253.         { Accumulate tallRect, which is occupied by the vertical scroll bar }
  254.         
  255.         SetRect(tallRect,theRect.right-15,
  256.                          theRect.top,
  257.                          theRect.right,
  258.                          theRect.bottom);
  259.         EraseRect(tallRect);
  260.         InvalRect(tallRect);
  261.         
  262.         { Accumulate wideRect, which is occupied by the horizontal scroll bar }
  263.         
  264.         SetRect(wideRect,theRect.left,
  265.                          theRect.bottom-15,
  266.                          theRect.right,
  267.                          theRect.bottom);
  268.         EraseRect(wideRect);
  269.         InvalRect(wideRect);
  270.     END; {InvalScroll}
  271.     
  272.     
  273.     PROCEDURE Deactivate(theWindow:WindowPtr);
  274.     
  275.     {Deactivate the scroll bars in theWindow in accordance
  276.      with the human interface guidelines. This means we must
  277.      erase everything enclosed by the control rectangles.}
  278.     
  279.     VAR
  280.         theControl:            ControlHandle;
  281.         theControlRect:        Rect;
  282.     
  283.     BEGIN
  284.     
  285.         {I always title my scroll bars 'MyVert' and 'MyHoriz'
  286.          so I can easily find them by walking the window's
  287.          control list.}
  288.          
  289.         theControl := WindowPeek(theWindow)^.controlList;
  290.         WHILE (theControl <> NIL) DO
  291.         BEGIN
  292.             IF (theControl^^.contrlTitle = 'MyVert') OR 
  293.                (theControl^^.contrlTitle = 'MyHoriz') THEN
  294.             BEGIN
  295.                 theControlRect := theControl^^.contrlRect;
  296.                 InsetRect(theControlRect,1,1);
  297.                 EraseRect(theControlRect);
  298.             END; {IF}
  299.             theControl := theControl^^.nextControl;
  300.         END; {WHILE}
  301.     END; {Deactivate}
  302.                 
  303.     
  304.     PROCEDURE HiliteScrollBars(theWindow:WindowPtr);
  305.     
  306.     {Reactivate the scroll bars; e.g., when we resume
  307.      under MultiFinder. More next month!}
  308.  
  309.     BEGIN
  310.         HiliteControl(vScroll,INTEGER(active));
  311.         HiliteControl(hScroll,INTEGER(active));
  312.     END; {HiliteScrollBars}
  313.  
  314.  
  315.     PROCEDURE MoveScrollBars(theWindow:WindowPtr);
  316.     
  317.     {Call this procedure after theWindow has changed size.
  318.      MoveScrollBars erases theWindow's scroll bars, resizes
  319.      them, and redraws them.}
  320.  
  321.     VAR
  322.         myWindowRect:            Rect;
  323.         vScrRect,hScrRect:        Rect;
  324.  
  325.     BEGIN
  326.         myWindowRect := theWindow^.portRect;
  327.         SetRect(hScrRect,myWindowRect.left - 1,
  328.                          myWindowRect.bottom - 15,
  329.                          myWindowRect.right - 14,
  330.                          myWindowRect.bottom + 1);
  331.         SetRect(vScrRect,myWindowRect.right - 15,
  332.                          myWindowRect.top - 1,
  333.                          myWindowRect.right + 1,
  334.                          myWindowRect.bottom - 14);
  335.         SetPort(theWindow);
  336.         ClipRect(myWindowRect);
  337.         
  338.         {Hide and resize the scroll bars to fit the new window size.}
  339.             
  340.         HideControl(hScroll);
  341.         HideControl(vScroll);
  342.         MoveControl(hScroll,hScrRect.left,hScrRect.top);
  343.         SizeControl(hScroll,(hScrRect.right - hScrRect.left),
  344.                             (hScrRect.bottom - hScrRect.top));
  345.         MoveControl(vScroll,vScrRect.left,vScrRect.top);
  346.         SizeControl(vScroll,(vScrRect.right - vScrRect.left),
  347.                             (vScrRect.bottom - vScrRect.top));
  348.         HiliteScrollBars(theWindow);
  349.         ShowControl(hScroll);
  350.         ShowControl(vScroll);
  351.     END; {MoveScrollBars}
  352.     
  353.     
  354.     PROCEDURE ScrollWithThumb(theControl:ControlHandle;theEventPoint:Point);
  355.  
  356.     BEGIN
  357.         {Next month!}
  358.     END; {ScrollWithThumb}
  359.         
  360.         
  361.     FUNCTION WhichDevice(thePoint:Point):GDHandle;
  362.     
  363.     {For machines that support color QuickDraw and
  364.      multiple screens, WhichDevice figures out which screen 
  365.      thePoint is on and returns a GDHandle to that screen. 
  366.      thePoint might be where the mouse was clicked, for 
  367.      example. Thanks to Greg Marriott for this code.}
  368.  
  369.     VAR
  370.         aDevice:    GDHandle;
  371.         foundOne:    BOOLEAN;
  372.     
  373.     BEGIN
  374.         aDevice := GetDeviceList;
  375.         foundOne :=    FALSE;
  376.         
  377.         {Walk the device list until thePoint is contained
  378.          in some device's screen rectangle.}
  379.  
  380.         WHILE (aDevice <> NIL) AND NOT foundOne DO
  381.         BEGIN
  382.             IF PtInRect(thePoint,aDevice^^.gdRect) THEN
  383.             BEGIN
  384.                 WhichDevice := aDevice;
  385.                 foundOne := TRUE;
  386.             END;
  387.             aDevice := aDevice^^.gdNextGD;
  388.         END;
  389.     END;    { WhichDevice }
  390.     
  391.     
  392.     FUNCTION MenuBarHeight: INTEGER;
  393.     
  394.     {Returns the height of the menubar in pixels, as
  395.      read from the low memory global mBarHeight.}
  396.     
  397.     CONST
  398.         mBarHeight    =    $BAA;
  399.         
  400.     VAR
  401.         menuBarHeightPtr:    ^INTEGER;
  402.         
  403.     BEGIN
  404.         menuBarHeightPtr := Pointer(mBarHeight);
  405.         MenuBarHeight := menuBarHeightPtr^;
  406.     END; {MenuBarHeight}
  407.     
  408.     
  409.     FUNCTION OnAScreen(theRect:Rect):BOOLEAN;
  410.     
  411.     {OnAScreen returns FALSE if all of a window's title
  412.      bar is off the screen or if any part of it is under
  413.      the menubar. The portRect of the window to be checked
  414.      should be passed in theRect.}
  415.  
  416.     CONST
  417.         titleBarHeight    =    18;
  418.         
  419.     VAR
  420.         deskRgn:            RgnHandle;
  421.         topLeft,topRight:    Point;
  422.  
  423.     BEGIN
  424.         deskRgn := GetGrayRgn;
  425.         topLeft.v := theRect.top - titleBarHeight;
  426.         topLeft.h := theRect.left + titleBarHeight;
  427.         topRight.v := topLeft.v;
  428.         topRight.h := theRect.right - titleBarHeight;
  429.         IF ((PtInRgn(topLeft,deskRgn)) OR (PtInRgn(topRight,deskRgn))) THEN
  430.             OnAScreen := TRUE
  431.         ELSE
  432.             OnAScreen := FALSE;
  433.     END; {OnAScreen}
  434.  
  435.  
  436.     PROCEDURE ZoomIt(theWindow:WindowPtr;partCode:INTEGER;clickedWhere:Point);
  437.     
  438.     {ZoomIt supports more elegant window zooming on multiple
  439.      screen systems. theWindow will zoom to fill whatever
  440.      screen the zoom box was on when it was clicked. The
  441.      window state toggles between original size and zoomed
  442.      size, as usual. Thanks to Greg Marriott for this code.}
  443.  
  444.     CONST
  445.         titleBarHeight    =    18;
  446.         
  447.     TYPE
  448.         WStatePtr        =    ^WStateData;
  449.         WStateHandle    =    ^WStatePtr;
  450.         
  451.     VAR
  452.         oldRect,newRect:    Rect;
  453.         maxHeight:            INTEGER;
  454.         
  455.     BEGIN
  456.         oldRect := theWindow^.portRect;
  457.         IF theEnv.hasColorQD THEN
  458.         BEGIN
  459.             newRect := WhichDevice(clickedWhere)^^.gdRect;
  460.             IF WhichDevice(clickedWhere) = GetMainDevice THEN
  461.                 newRect.top := newRect.top + MenuBarHeight;
  462.         END
  463.         ELSE
  464.             newRect := GetGrayRgn^^.rgnBBox;
  465.         newRect.left := newRect.left + 2;
  466.         newRect.top := newRect.top + titleBarHeight + 2;
  467.         newRect.right := newRect.right - 3;
  468.         newRect.bottom := newRect.bottom - 3;
  469.         IF NOT EqualRect(oldRect,newRect) THEN
  470.             WITH WindowPeek(theWindow)^ DO
  471.                 WStateHandle(dataHandle)^^.stdState := newRect;
  472.         SetPort(theWindow);
  473.         EraseRect(whichWindow^.portRect);        
  474.         InvalRect(whichWindow^.portRect);
  475.         ZoomWindow(theWindow,partcode,FALSE);
  476.     END;    { ZoomIt }
  477.             
  478.             
  479.     {$I XCmdGlue.inc}
  480.     
  481.     
  482.     PROCEDURE Fail(errStr:Str255);
  483.  
  484.     {Fail returns errStr to HyperCard and exits the XCMD.
  485.      errStr can then be checked by inspecting HyperCard's
  486.      global variable "the result." See "XCMD's for Hyper-
  487.      Card" by Gary Bond (MIS Press, 1988) for more details.
  488.  
  489.      © 1988 by Gary Bond
  490.      All rights reserved.
  491.      You may use this code for NON-COMMERCIAL purposes.}
  492.  
  493.     BEGIN
  494.         paramPtr^.returnValue := PasToZero(errStr);
  495.         SysBeep(1);
  496.         EXIT(Window);
  497.     END; {Fail}
  498.     
  499.     
  500.     PROCEDURE CheckParamCount;
  501.  
  502.     {CheckParamCount sees if the number of parameters
  503.      passed to the XCMD matches the number expected. If
  504.      not, we exit from the XCMD with an error message.
  505.      See "XCMD's for HyperCard" by Gary Bond (MIS Press,
  506.      1988) for more details.
  507.  
  508.      © 1988 by Gary Bond
  509.      All rights reserved.
  510.      You may use this code for NON-COMMERCIAL purposes.}
  511.  
  512.     VAR
  513.         numParams : INTEGER;
  514.         
  515.     BEGIN
  516.         numParams := paramPtr^.paramCount;
  517.         IF(numParams <> minParamCount) THEN
  518.             Fail('Form: HyperWindow "Window Title",top,left,bottom,right');
  519.     END;    {CheckParamCount}
  520.     
  521.     
  522.     FUNCTION GetHCVersion:Str255;
  523.     
  524.     {Return a string containing the version of HyperCard
  525.      being used; e.g., '1.2'}
  526.     
  527.     BEGIN
  528.         ZeroToPas(EvalExpr('the version')^,GetHCVersion);
  529.     END; {GetHCVersion}
  530.     
  531.     
  532.     PROCEDURE HideWindoids;
  533.  
  534.     {Get and save the visible state of the tool, pattern,
  535.      message and fatbits windoids; then hide them if they
  536.      are showing.}
  537.  
  538.     VAR
  539.         toolH,patH,msgH,fatH:    Handle;
  540.         
  541.         PROCEDURE HideFatBits;
  542.  
  543.         {HyperCard does not have a built-in command for hiding
  544.          and showing the fatbits windoid, so we have to do it
  545.          ourselves. HideFatBits walks the window list until it
  546.          finds a window with title "FatBits," then hides it if
  547.          the visible field of its WindowRecord is true. 
  548.          HideFatBits also saves the WindowPtr to the fatbits
  549.          windoid so we can use it later (e.g., to show the
  550.          windoid again).}
  551.  
  552.         CONST
  553.             windowList            =    $9D6; {Low memory global location.}
  554.  
  555.         VAR
  556.             theWindow:        WindowPeek;
  557.             theWindowPtr:    ^WindowPtr;
  558.         
  559.         BEGIN
  560.             theWindowPtr := Pointer(windowList);
  561.             theWindow := WindowPeek(theWindowPtr^);
  562.             fatVis := FALSE;
  563.             WHILE (theWindow <> NIL) DO
  564.             BEGIN
  565.                 IF (theWindow^.titleHandle^^ = 'FatBits') THEN
  566.                 BEGIN
  567.                     fatBitsWindow := WindowPtr(theWindow);
  568.                     IF (theWindow^.visible = TRUE) THEN
  569.                     BEGIN
  570.                         fatVis := TRUE;
  571.                         HideWindow(fatBitsWindow);
  572.                         theWindow := NIL;
  573.                     END;
  574.                 END;
  575.                 IF (theWindow <> NIL) THEN
  576.                     theWindow := WindowPeek(theWindow)^.nextWindow;
  577.             END; {WHILE}
  578.         END; {HideFatBits}
  579.         
  580.     BEGIN {HideWindoids}
  581.  
  582.         {Get visible state of windoids.}
  583.  
  584.         toolH := EvalExpr('visible of tool window');
  585.         ZeroToPas(toolH^,toolStr);
  586.         DisposHandle(toolH);
  587.         toolVis := StrToBool(toolStr);
  588.  
  589.         patH := EvalExpr('visible of pattern window');
  590.         ZeroToPas(patH^,patStr);
  591.         DisposHandle(patH);
  592.         patVis := StrToBool(patStr);
  593.  
  594.         msgH := EvalExpr('visible of message window');
  595.         ZeroToPas(msgH^,msgStr);
  596.         DisposHandle(msgH);
  597.         msgVis := StrToBool(msgStr);
  598.         
  599.         {Hide the ones that are showing.}
  600.         
  601.         HideFatBits;
  602.         
  603.         IF toolVis THEN
  604.             SendHCMessage('hide tool window');
  605.         IF patVis THEN
  606.             SendHCMessage('hide pattern window');
  607.         IF msgVis THEN
  608.             SendHCMessage('hide message window');
  609.     END;    {HideWindoids}
  610.     
  611.     
  612.     PROCEDURE ShowWindoids;
  613.  
  614.     {This routine assumes HideWindoids has been called
  615.      before. ShowWindoids restores the visible state of
  616.      the windoids to that saved by HideWindoids.}
  617.  
  618.     BEGIN
  619.         IF toolVis THEN
  620.             SendHCMessage('show tool window');
  621.         IF patVis THEN
  622.             SendHCMessage('show pattern window');
  623.         IF msgVis THEN
  624.             SendHCMessage('show message window');
  625.  
  626.         {As in HideWindoids, we must take care of the FatBits
  627.          windoid ourselves.}
  628.  
  629.         IF fatVis THEN
  630.         BEGIN
  631.             ShowWindow(fatBitsWindow);
  632.             SelectWindow(fatBitsWindow);
  633.         END;
  634.     END;    {ShowWindoids}
  635.     
  636.     
  637.     PROCEDURE ToggleMenuBar;
  638.     
  639.     {Set the visible of the menubar to not the visible of
  640.      the menubar.}
  641.         
  642.     BEGIN
  643.         IF MenuBarHeight = 0 THEN
  644.             SendHCMessage('show menuBar')
  645.         ELSE
  646.             SendHCMessage('hide menuBar');
  647.     END; {ToggleMenuBar}
  648.         
  649.     
  650.     PROCEDURE GetHCBitMap;
  651.     
  652.     BEGIN
  653.         {Next month!}
  654.     END; {GetHCBitMap}
  655.     
  656.     
  657.      PROCEDURE AdjustCursor;
  658.     
  659.     {AdjustCursor changes cursorRgn to the region that contains
  660.      the cursor.  As soon as the cursor moves out of cursorRgn, we
  661.      get an event and can change the cursor and cursorRgn again.
  662.      cursorRgn is either the content region of our window or
  663.      the region containing everything BUT the content region of our
  664.      window.}
  665.       
  666.     VAR
  667.         mousePt:        Point;
  668.         myWinContRect:    Rect;
  669.         myWinContRgn:    RgnHandle;
  670.         deskRgn:        RgnHandle;
  671.         handHdl:        CursHandle;
  672.     
  673.     BEGIN
  674.         SetPort(myWindow);
  675.         GetMouse(mousePt);
  676.         LocalToGlobal(mousePt);
  677.         myWinContRgn := NewRgn;
  678.         
  679.         {Calculate the "work region" of our window, which is its
  680.          content region minus the scroll bars and grow icon. 
  681.          This is the region within which we want the cursor to 
  682.          change to HyperCard's browse tool, and outside of which 
  683.          we want it to be an arrow.}
  684.         
  685.         WITH WindowPeek(myWindow)^.contRgn^^.rgnBBox DO
  686.             SetRect(myWinContRect,left, top, right - 15, bottom - 15);
  687.         RectRgn(myWinContRgn,myWinContRect);
  688.                                 
  689.         IF PtInRect(mousePt,myWinContRect) THEN
  690.         BEGIN
  691.         
  692.             {The cursor is in the work region of our window. Set to browse tool.}
  693.             
  694.             handHdl := GetCursor(browseTool);
  695.             IF (handHdl <> NIL) THEN
  696.                 SetCursor(handHdl^^)
  697.             ELSE
  698.                 
  699.                 {Set to arrow if can't find browse tool resource.}
  700.                 
  701.                 InitCursor;
  702.             
  703.             {Set the cursor region equal to our window's work region.}
  704.             
  705.             SetEmptyRgn(cursorRgn);
  706.             CopyRgn(myWinContRgn,cursorRgn);
  707.         END
  708.         ELSE
  709.         BEGIN
  710.         
  711.             {The cursor is outside our window. Set to arrow.}
  712.             
  713.             InitCursor;
  714.             
  715.             {Get the current desktop region.}
  716.             
  717.             deskRgn := GetGrayRgn;
  718.             
  719.             {Set cursorRgn to the desktop region's bounding box.  It is
  720.              important to add the menu bar area to cursorRgn too.}
  721.              
  722.             SetRectRgn(cursorRgn, deskRgn^^.rgnBBox.left,
  723.                                   deskRgn^^.rgnBBox.top,
  724.                                   deskRgn^^.rgnBBox.right,
  725.                                   deskRgn^^.rgnBBox.bottom);
  726.                                   
  727.             {Punch out our window's content region from the big region.}
  728.             
  729.             DiffRgn(cursorRgn,myWinContRgn,cursorRgn);
  730.         END;
  731.         DisposeRgn(myWinContRgn);
  732.     END; {AdjustCursor}
  733.  
  734.  
  735. BEGIN {Main Program}
  736.  
  737.     {Check the HyperCard version.  Must be 1.2 or greater.}
  738.     
  739.     IF GetHCVersion < '1.2' THEN
  740.         Fail('Sorry, must have HyperCard 1.2 or greater.');
  741.  
  742.     {Save thy grafPort upon entering!}
  743.  
  744.     GetPort(HCPort);
  745.     
  746.     {Check and reset our environment.}
  747.     
  748.     CheckParamCount;
  749.     FlushEvents(everyEvent,0);
  750.     InitCursor;
  751.     
  752.     {Find out what kind of machine we're running on.}
  753.     
  754.     envError := SysEnvirons(1,theEnv);
  755.     IF (envError <> noErr) THEN
  756.         Fail('SysEnvirons call failed.');
  757.  
  758.     {Convert HyperTalk input parameters for use here.}
  759.     
  760.     ZeroToPas(paramPtr^.params[1]^,wTitle);
  761.     ZeroToPas(paramPtr^.params[2]^,wT);
  762.     ZeroToPas(paramPtr^.params[3]^,wL);
  763.     ZeroToPas(paramPtr^.params[4]^,wB);
  764.     ZeroToPas(paramPtr^.params[5]^,wR);
  765.         
  766.     wTop := INTEGER(StrToNum(wT));
  767.     wLeft := INTEGER(StrToNum(wL));
  768.     wBottom := INTEGER(StrToNum(wB));
  769.     wRight := INTEGER(StrToNum(wR));
  770.         
  771.     {If window size parameters are too small or illegal, set
  772.      the window to a predefined minimum size.}
  773.  
  774.     IF ((wRight - wLeft) < smallestWidth) THEN
  775.         wRight := wLeft + smallestWidth;
  776.     IF ((wBottom - wTop) < smallestHeight) THEN
  777.         wBottom := wTop + smallestHeight;
  778.         
  779.     {Make sure the user is not trying to draw the window off
  780.      the screen or under the menubar.}
  781.  
  782.     SetRect(wRect,wLeft,wTop,wRight,wBottom);
  783.     IF NOT OnAScreen(wRect) THEN
  784.         Fail('You are trying to draw your window off the screen!');
  785.  
  786.     {Get the bounds of the desktop.}
  787.  
  788.     screenRect := GetGrayRgn^^.rgnBBox;
  789.     
  790.     {If we have a small screen, make a note of it so we can hide the
  791.      card window during context switches under MultiFinder.}
  792.      
  793.     ZeroToPas(EvalExpr('item 3 of the screenRect')^,widthStr);
  794.     screenWidth := INTEGER(StrToNum(widthStr));
  795.     ZeroToPas(EvalExpr('item 4 of the screenRect')^,heightStr);
  796.     screenHeight := INTEGER(StrToNum(heightStr));
  797.     
  798.     IF (screenWidth = 512) AND (screenHeight = 342) THEN
  799.            smallScreen := TRUE
  800.     ELSE
  801.         smallScreen := FALSE;
  802.     
  803.     HideWindoids;
  804.  
  805.     IF MenuBarHeight > 0 THEN
  806.         menuWasHidden := FALSE
  807.     ELSE
  808.         menuWasHidden := TRUE;
  809.     
  810.       {This is for scrolling and will be explained next month.}
  811.  
  812.     theOffScrHandle := OffScrHandle(NewHandle(SizeOf(OffScrRecord)));
  813.     IF MemError <> noErr THEN
  814.         Fail('Out of memory.  Buy more.');
  815.         
  816.     myDocWidth := HCWidth + padding;
  817.     myDocHeight := HCHeight + padding;
  818.  
  819.     WITH theOffScrHandle^^ DO
  820.     BEGIN
  821.         {Next month!}
  822.     END;
  823.     
  824.     GetHCBitMap;
  825.     
  826.     {Draw the window!}
  827.     
  828.     myWindow := NewWindow(@wRecord,wRect,wTitle,TRUE,zoomDocProc,
  829.                           WindowPtr(-1),TRUE,1);
  830.     IF (myWindow = NIL) THEN
  831.     BEGIN
  832.         ShowWindoids;
  833.         Fail('Not enough memory to draw window.');
  834.     END
  835.     ELSE
  836.     BEGIN
  837.  
  838.         {This is for scrolling. Stay tuned....}
  839.  
  840.         SetWRefCon(myWindow,LONGINT(theOffScrHandle));
  841.         InitBlit(myWindow);
  842.         DrawGrowIcon(myWindow);
  843.         theScrollHandle := ScrollHandle(NewHandle(SizeOf(ScrollRecord)));
  844.         IF MemError <> noErr THEN
  845.             Fail('Out of memory.  Buy more.');
  846.  
  847.         {Draw horizontal and vertical scroll bars in our 
  848.          window.}
  849.  
  850.         hScroll := CreateHScrollBar(myWindow,0,0,myDocWidth,LONGINT(theScrollHandle));
  851.         vScroll := CreateVScrollBar(myWindow,0,0,myDocHeight,LONGINT(theScrollHandle));
  852.         HiliteScrollBars(myWindow);
  853.         DrawContents(myWindow);
  854.         SetRect(dragRect,screenRect.left + 4,
  855.                          screenRect.top,
  856.                          screenRect.right - 4,
  857.                          screenRect.bottom - 4);
  858.         largestHeight := screenRect.bottom - screenRect.top;
  859.         largestWidth := screenRect.right - screenRect.left;
  860.         SetRect(winSizeLimits,smallestWidth,
  861.                               smallestHeight,
  862.                               largestWidth,
  863.                               largestHeight);
  864.             
  865.         HCRefresh := 'Go to this card';
  866.         cursorRgn := NewRgn;
  867.         inBackGround := FALSE;
  868.         DoneFlag := FALSE;
  869.         REPEAT
  870.  
  871.             {Call WaitNextEvent, if available. Otherwise call
  872.              GetNextEvent.}
  873.  
  874.             IF hasWaitNextEvent THEN
  875.                 HaveEvent := WaitNextEvent(everyEvent,myEvent,30,cursorRgn)
  876.             ELSE
  877.             BEGIN
  878.                 HaveEvent := GetNextEvent(everyEvent,myEvent);
  879.                 AdjustCursor;
  880.             END;
  881.             IF HaveEvent THEN
  882.             BEGIN
  883.                 IF (myEvent.what = app4Evt) THEN
  884.  
  885.                     {Pre-process app4Evt's fed to us by MultiFinder.}
  886.  
  887.                     CASE BSR(myEvent.message,24) OF
  888.                     
  889.                         MouseMovedEvt:
  890.                             AdjustCursor;
  891.                         
  892.                         SuspendResumeEvt:
  893.                         BEGIN
  894.                             myEvent.what := activateEvt;
  895.                                 
  896.                             { Resume event }
  897.                                 
  898.                             IF (BAND(myEvent.message,SuspendEventMask) <> 0) THEN
  899.                                 inBackground := FALSE
  900.                             ELSE
  901.                                 
  902.                             { Suspend event }
  903.                             
  904.                                 inBackground := TRUE;
  905.                                 
  906.                             myEvent.message := LONGINT(myWindow);
  907.                         END; {SuspendResumeEvt}
  908.                             
  909.                     END;    {CASE BSR}
  910.             END;    {IF HaveEvent}
  911.  
  912.             CASE myEvent.what OF
  913.                 
  914.                 mouseDown:
  915.                 BEGIN
  916.                     partCode := FindWindow(myEvent.where,whichWindow);
  917.                     IF (whichWindow = myWindow) THEN
  918.                     BEGIN
  919.  
  920.                         {Deal with mouse hits to our window.}
  921.  
  922.                         CASE partCode OF
  923.                             
  924.                             inDrag:
  925.                             BEGIN
  926.                                 SelectWindow(whichWindow); {DragWindow bug}
  927.                                 DragWindow(whichWindow,myEvent.where,dragRect);
  928.                                 SendCardMessage(HCrefresh);
  929.                                 AdjustCursor;
  930.                             END;
  931.  
  932.                             inGrow:
  933.                             BEGIN
  934.                                 IF StillDown THEN    {GrowWindow bug}
  935.                                 BEGIN
  936.                                     oldSize := whichWindow^.portRect;
  937.                                     newSize := GrowWindow(whichWindow,myEvent.where,winSizeLimits);
  938.                                     IF (newSize <> 0) THEN
  939.                                     BEGIN
  940.                                         InvalScroll(whichWindow);
  941.                                         SizeWindow(whichWindow,LOWORD(newSize),HIWORD(newSize),FALSE);
  942.                                         InvalContents(whichWindow,oldSize);
  943.                                         DrawGrowIcon(whichWindow);
  944.                                         MoveScrollBars(whichWindow);
  945.                                     END; {IF newSize}
  946.                                 END; {IF StillDown}
  947.                             END; {inGrow}
  948.                                 
  949.                             inZoomIn,inZoomOut:
  950.                             BEGIN
  951.                                 IF (TrackBox(whichWindow,myEvent.where,partCode)) THEN
  952.                                 BEGIN
  953.                                     InvalScroll(whichWindow);
  954.                                     ZoomIt(whichWindow,partCode,myEvent.where);
  955.                                     InvalContents(whichWindow,oldSize);
  956.                                     DrawGrowIcon(whichWindow);
  957.                                     MoveScrollBars(whichWindow);
  958.                                 END; {IF TrackBox}
  959.                             END; {inZoomIn,inZoomOut}
  960.                                 
  961.                             inContent:
  962.                             BEGIN
  963.                                 SetPort(whichWindow);
  964.                                 eventPoint := myEvent.where;
  965.                                 GlobalToLocal(eventPoint);
  966.                                 controlCode := FindControl(eventPoint,whichWindow,whichControl);
  967.                                 ClipRect(whichWindow^.portRect);
  968.                                 IF (controlCode = inThumb) THEN
  969.                                     ScrollWithThumb(whichControl,eventPoint)
  970.                                 ELSE IF (controlCode <> 0) THEN
  971.                                     dummy := TrackControl(whichControl,eventPoint,@MyScroll);
  972.                             END; {inContent}
  973.                                     
  974.                             inGoAway:
  975.                             BEGIN
  976.                                 IF(TrackGoAway(whichWindow,myEvent.where)) THEN
  977.                                     DoneFlag := TRUE;
  978.                             END; {inGoAway}
  979.                             
  980.                         END; {CASE partCode}
  981.                     END
  982.                     ELSE
  983.                     BEGIN
  984.                         IF MenuBarHeight > 0 THEN
  985.                         BEGIN
  986.                             FlashMenuBar(0);
  987.                             Delay(LONGINT(6),dontCare);
  988.                             FlashMenuBar(0);
  989.                         END; {IF MenuBarHeight}
  990.                     END; {IF FindWindow...ELSE}
  991.                 END; {mouseDown}
  992.                     
  993.                 activateEvt:
  994.                 BEGIN
  995.                     IF(WindowPtr(myEvent.message) = myWindow) THEN
  996.                     BEGIN
  997.                         SetPort(myWindow);
  998.                         ClipRect(myWindow^.portRect);
  999.                         DrawGrowIcon(myWindow);
  1000.                         IF inBackground THEN
  1001.                         BEGIN
  1002.  
  1003.                             {We've been sent behind another application
  1004.                              under MultiFinder, so deactivate the scroll
  1005.                              bars and show the menubar if it was hidden.}
  1006.  
  1007.                             Deactivate(myWindow);
  1008.                             IF smallScreen THEN
  1009.                                 ShowHide(WindowPtr(HCPort),FALSE);
  1010.                             IF MenuBarHeight = 0 THEN
  1011.                             BEGIN
  1012.                                 SendHCMessage('show menubar');
  1013.                                 menuWasHidden := TRUE;
  1014.                             END
  1015.                             ELSE
  1016.                                 menuWasHidden := FALSE;
  1017.                         END
  1018.                         ELSE
  1019.                         BEGIN
  1020.  
  1021.                             {We've been brought to the front under Multi-
  1022.                              Finder, so reactivate the scroll bars and
  1023.                              hide the menubar if it was hidden before.}
  1024.  
  1025.                             ShowHide(WindowPtr(HCPort),TRUE);
  1026.                             IF menuWasHidden THEN
  1027.                                 SendHCMessage('hide menubar');
  1028.                             DrawControls(myWindow);
  1029.                             HiliteScrollBars(myWindow);
  1030.                             FlushEvents(everyEvent,0);
  1031.                         END; {IF inBackground}
  1032.                     END; {IF WindowPtr}
  1033.                 END; {activateEvt}
  1034.                     
  1035.                 updateEvt:
  1036.                 BEGIN
  1037.                 
  1038.                     {Handle updates to our window.}
  1039.                     
  1040.                     IF(WindowPtr(myEvent.message) = myWindow) THEN
  1041.                     BEGIN
  1042.                     
  1043.                         {Always do this stuff}
  1044.                         
  1045.                         SetPort(myWindow);
  1046.                         BeginUpdate(myWindow);
  1047.                         ClipRect(myWindow^.portRect);
  1048.                         DrawGrowIcon(myWindow);
  1049.  
  1050.                         {Always do this stuff under single Finder but
  1051.                          only if in foreground under MultiFinder}
  1052.  
  1053.                         IF NOT inBackground THEN
  1054.                         BEGIN
  1055.                             HiliteScrollBars(myWindow);
  1056.                             DrawControls(myWindow);
  1057.                             AdjustCursor;
  1058.                         END;
  1059.                         
  1060.                         {Always do this stuff}
  1061.                         
  1062.                         DrawContents(myWindow);
  1063.                         EndUpdate(myWindow);
  1064.                     END {IF myEvent.message}
  1065.  
  1066.                     {Handle updates to HyperCard's card window.}
  1067.  
  1068.                     ELSE IF (WindowPtr(myEvent.message) = WindowPtr(HCPort)) THEN
  1069.                     BEGIN
  1070.                         SendHCMessage(HCRefresh);
  1071.  
  1072.                         {Must zero out card window's update region
  1073.                          ourselves because the SendHCMessage call
  1074.                          doesn't do it, and we'll wind up in an
  1075.                          infinite loop if we don't.}
  1076.  
  1077.                         BeginUpdate(WindowPtr(HCPort));
  1078.                         EndUpdate(WindowPtr(HCPort));
  1079.                     END; {IF... ELSE}
  1080.                 END; {updateEvt}
  1081.                     
  1082.                 keyDown:
  1083.                 BEGIN
  1084.                     IF(BitAnd(myEvent.modifiers,cmdKey) <> 0) THEN
  1085.                     BEGIN
  1086.                         charCode := BitAnd(myEvent.message,charCodeMask);
  1087.                         
  1088.                         {Pressing command-spacebar toggles the menubar.}
  1089.                         
  1090.                         IF(CHR(charCode) = ' ') THEN
  1091.                             ToggleMenuBar
  1092.  
  1093.                         {Pressing command-W closes the window and exits
  1094.                           the XCMD.}
  1095.  
  1096.                         ELSE IF(CHR(charCode) = 'w') THEN
  1097.                             DoneFlag := True;
  1098.                     END;
  1099.                 END;
  1100.             END; {CASE myEvent.what}
  1101.                 
  1102.         UNTIL (DoneFlag = True);
  1103.  
  1104.         {Clean up and get outta here!}
  1105.  
  1106.         DisposeRgn(cursorRgn);
  1107.         DisposHandle(Handle(theOffScrHandle));
  1108.         DisposHandle(Handle(theScrollHandle));
  1109.         CloseWindow(myWindow);
  1110.         SendCardMessage(HCrefresh);
  1111.         ShowWindoids;
  1112.         InitCursor;
  1113.         FlushEvents(everyEvent,0);
  1114.         
  1115.         {Restore thy grafPort}
  1116.         
  1117.         SetPort(HCPort);
  1118.     END; {IF myWindow...ELSE}
  1119. END; {Main}
  1120. END. {Window}